package com.alibaba.aliper.server.controller.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.alibaba.aliper.server.model.interfaces.AliperControll;

public class AliperSocket implements Runnable {
	private AliperSocket(){}
	private static AliperSocket aliperSocket = new AliperSocket();
	
	public static AliperSocket getAliperSocket(){
		return aliperSocket;
	}
	
	private AliperControll server = null;
	public void setAliperServer(AliperControll server) {
		this.server = server;
	}

	private int port = 8456;
	private int maxConnections = 10;
	private boolean running = false;

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public int getMaxConnections() {
		return maxConnections;
	}

	public void setMaxConnections(int maxConnections) {
		this.maxConnections = maxConnections;
	}



	public static void main(String[] args) {
		Matcher matcher = reportPattern.matcher("agent:\"agentname\" chart:\"chartname\" line:\"linename\" point.x:\"pointx\" point.y:\"pointy\"");
		matcher.find();
		for(int i = 1; i < 6;++i)
		System.out.println(matcher.group(i));
	}

	@Override
	public void run() {
		try {
			serverSocket = new ServerSocket(this.port);
			running = true;
			while (running) {
				Socket socket = serverSocket.accept();
				Worker worker = null;
				synchronized (workers) {
					if(workers.size() < this.maxConnections){
						worker = new Worker(socket);
						workers.add(worker);
					}
				}
				if(worker != null){
					Thread thread = new Thread(worker);
					thread.setDaemon(true);
					thread.start();
				}
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	private ServerSocket serverSocket = null;
	private HashSet<Worker> workers = new HashSet<Worker>();
	private static Pattern reportPattern = Pattern.compile("\\s*project\\s*:\\s*\"([^\"]*)\"\\s*agent\\s*:\\s*\"([^\"]*)\"\\s*chart\\s*:\\s*\"([^\"]*)\"\\s*line\\s*:\\s*\"([^\"]*)\"\\s*point\\.x\\s*:\\s*\"([^\"]*)\"\\s*point\\.y\\s*:\\s*\"([^\"]*)\"");
	public class Worker implements Runnable {
		//private Logger logger = Logger.getLogger(getClass());
		public Worker(Socket socket) {
			this.socket = socket;
		}

		private Socket socket;

		@Override
		public void run() {
			try {
				BufferedReader reader = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
				while (true) {
					String line = reader.readLine();
					Matcher matcher = reportPattern.matcher(line);
					try{
						accessReport(matcher);
					} catch (IllegalArgumentException e) {
						//logger.error("report message \""+line + "\" does not match my pattern!",e);
						throw e;
					} catch (Exception e) {
						//logger.error("error", e);
						throw e;
					} 
				}
			} catch (Exception e) {
				try {
					this.socket.close();
				} catch (IOException e1) {
				//	logger.error("error", e1);
					e.printStackTrace();
				}
				synchronized (AliperSocket.this.workers) {
					AliperSocket.this.workers.remove(this);
				}
				//logger.error("error when read data from client!",e);
				e.printStackTrace();
			}
		}

		private void accessReport(Matcher matcher) {
			if(!matcher.find()){
				throw new IllegalArgumentException("match faild!");
			}
			String project = matcher.group(1);
			String agent = matcher.group(2);
			String chart = matcher.group(3);
			String line = matcher.group(4);
			long time = Long.parseLong(matcher.group(5));
			double value = Double.parseDouble(matcher.group(6));
			AliperSocket.this.server.getAgentOnCreate(project,agent).getChartOnCreate(chart).report(line,time, value);
		}

	}
	public void close() throws IOException {
		this.running = false;
		this.serverSocket.close();
	}
	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		this.close();
	}
}
